using System;
using System.Linq.Expressions;
using System.Reflection;

namespace jSLCore.Service.Workflow.Linq.jProperty
{
    public class jPropertyVisiter : ExpressionVisitor
    {protected override Expression VisitMember(MemberExpression node)
        {
            var memberInfo = node.Member;
            var customAttributes = jExpressionPropertyHelper.GetjExpressionPropertyAttribute(memberInfo);
            if(customAttributes!=null)
            {
                    var jPropertyAttribute = customAttributes;
                    var propertyName = jPropertyAttribute.PropertyName;
                    var subPropertyName = jPropertyAttribute.SubPropertyName;

                    if (propertyName != null)
                    {

                        var returnExpression = Expression.Property(node.Expression, propertyName);

                        var propertyType = memberInfo.DeclaringType.GetProperty(propertyName).PropertyType;

                        if (subPropertyName != null)
                        {
                            propertyType = propertyType.GetProperty(subPropertyName).PropertyType;

                            returnExpression = Expression.Property(returnExpression, subPropertyName);
                        }

                        var visitMember = Visit(returnExpression);

                        if (propertyType != ((PropertyInfo)memberInfo).PropertyType)
                            visitMember = Expression.MakeUnary(ExpressionType.Convert, visitMember, node.Type);

                        return visitMember;
                    }
                    else
                    {//trying to get lambda from static field

                        var lambdaExpression = jExpressionPropertyHelper.GetLambdaExpressionFromjProperty(memberInfo);
                        var parameterVisitor = new ReplaceParameterVisitor(lambdaExpression.Parameters[0],(ParameterExpression) node.Expression);
                        var returnExpression = lambdaExpression.Body;
                        returnExpression = parameterVisitor.Visit(returnExpression);
                        return Visit(returnExpression);
                        //return Visit(lambdaExpression);
                    }
             }
        return node;
        }

        protected override Expression VisitUnary(UnaryExpression node)
        {
            /*if(node.NodeType==ExpressionType.Convert)
            {
                return Visit(node.Operand);
            }*/
            var operand = Visit(node.Operand);
            
            if(operand!=node.Operand)
            {
                return Expression.MakeUnary(node.NodeType, operand, node.Type, node.Method);
            }

            return node;
            
        }


    }

    public class ReplaceParameterVisitor:ExpressionVisitor
    {
        private readonly ParameterExpression _newExpression;
        private readonly ParameterExpression _oldParameter;

        public ReplaceParameterVisitor(ParameterExpression oldParameter, ParameterExpression newExpression)
        {
            _newExpression = newExpression;
            _oldParameter = oldParameter;
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            if(node==_oldParameter)
                return _newExpression;
            else
            {
                return node;
            }
        }
    }
}